import { CustomEventListener } from "../data/CustomEventListener";

export type NetData = (string | ArrayBufferLike | Blob | ArrayBufferView);

// 配置
const RECONN_INVTEVAL: number = 8;
const RECONN_LIMIT: number = 8;
export interface IReconnShowContent {
    index: number;
    total: number;
}
export class DoWebSock {
    private _reconnectHandle: () => void = null;
    private _isLink: boolean = false;
    // private _isReconn: boolean = false;
    private _allowReconn: boolean = false;
    private _reconnCount: number = 0;
    private _connFailHandle: () => void = null;
    private _connSuccHandle: () => void = null;

    private _wsiSendBinary: WebSocket = null;

    private _url: string = null;

    constructor(reconnectHandle: () => void) {
        this._reconnectHandle = reconnectHandle;
        this.reset();
    }

    private reset() {
        this._isLink = false;
        // this._isReconn = false;
        this._allowReconn = true;
        this._reconnCount = 0;
    }

    
    public connect(url: string, connect_successful: () => void, connect_failed: () => void) {
        this.ws_clear();

        this._url = url;
        this._wsiSendBinary = new WebSocket(url);
        this._wsiSendBinary.binaryType = "arraybuffer";
        this._connSuccHandle = connect_successful;
        this._connFailHandle = connect_failed;

        this._wsiSendBinary.onopen = this.onOpen.bind(this);
        this._wsiSendBinary.onmessage = this.onReceive.bind(this);
        this._wsiSendBinary.onerror = this.onError.bind(this);
        this._wsiSendBinary.onclose = this.onClose.bind(this);

        console.log("DoWebSock connect url : "+url);
    }

    // -------------------------------------------------------------------------
    // websocket回调

    private onOpen(evt) {
        console.log("DoWebSock onOpen");
        // 更新状态
        this._isLink = true;
        // this._isReconn = false;
        this._allowReconn = true;
        this._reconnCount = 0;
        // g_notifyer.notify_frame_event("core_notify_ws_open");

        // 认证ws,认证的ws才会连接
        // console.log("DoWebSock ws_open -->认证ws");
        // this._confirmHandle();
        this._connSuccHandle();

        console.log("DoWebSock ws_open end");
    }

    private onReceive(evt) {
        let msg = evt.data;
        if (!msg) {
            console.warn("DoWebSock onReceive !msg");
            return;
        }

        if (typeof (msg) == 'string') {
            console.warn("DoWebSock onReceive msg is string");
            return;
        }
        let binary = new Uint8Array(msg);
        let ws_msg_data = BaseResponse.Response.decode(binary);
        let ws_msg = ResponseProto.decode(ws_msg_data.data);
        var cmd = ws_msg.cmd;

        // 所有处理交给上层,这里收到什么都往外扔
        // cc.log("DoWebSock ws_receive #### 转发消息 cmd：", cmd);
        CustomEventListener.dispatchEvent("core_notify_ws_response", {
            "event_name": cmd,
            "response_data": ws_msg
        });
    }

    private onError(evt) {
        console.log("DoWebSock ws_error !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        // g_notifyer.notify_ui_event("core_notify_ws_error");

        // 更新状态
        this._isLink = false;
        // this._isReconn = false;

        // 失败回调
        if (this._connFailHandle) {
            console.log("DoWebSock ws_error #### 失败回调");
            this._connFailHandle();
        }

        console.log("DoWebSock ws_error end");
    }

    private onClose(evt) {
        console.log("DoWebSock ws_close !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        CustomEventListener.dispatchEvent("core_notify_ws_close");

        // 走到此处肯定已经被close过了，所以直接置空！！！
        this._wsiSendBinary = null;

        if (this._allowReconn == false) {
            console.log("DoWebSock ws_close 不允许重连！！");
            return;
        }

        // 多次重连失败-->跳转登录
        if (this._reconnCount >= RECONN_LIMIT) {
            console.log("DoWebSock ws_close 重连失败超过预设" + RECONN_LIMIT + "次！");
            CustomEventListener.dispatchEvent("core_notify_ws_reconnect_fail");
            return;
        }

        // 更新状态
        this._isLink = false;
        // this._isReconn = false;
        CustomEventListener.dispatchEvent("core_notify_ws_loading");

        // token为空，等待登录中，不再自动重连
        if (!globalThis.account_token || globalThis.account_token === "undefined" || globalThis.account_token === "") {
            console.log("\n\nwebsocket ############ ws_close #### token为空，等待登录中，不再自动重连 \n\n");
            CustomEventListener.dispatchEvent("core_notify_ws_unloading");
            return;
        }

        this.startReconnect();

        console.log("DoWebSock ws_close end");       
    }

    public startReconnect() {
        let self = this;
        console.log("DoWebSock start_reconnect 重连（立即）（延时）");

        // 重连（立即）（延时）
        this._reconnCount++;
        if (this._reconnCount == 1) {
            console.log("DoWebSock start_reconnect #### 第 " + this._reconnCount + "次 （立即）重连！！");
            let temp_data : IReconnShowContent = {
                index: this._reconnCount,
                total: RECONN_LIMIT
            }
            CustomEventListener.dispatchEvent("core_notify_ws_loading", { "response": temp_data });

            this._reconnectHandle();
        } else {
            setTimeout(()=>{self.dalayReconnect}, RECONN_INVTEVAL);
            // cc.director.getScheduler().schedule(this, this.on_ws_reconnect_delay, 0, 0, 3, false, "reconnectTest");
        }
    }

    private dalayReconnect(dt: number) {
        let self = this;
        console.log("DoWebSock on_ws_reconnect_delay #### 第 " + self._reconnCount + "次 （延时）重连！！");
        let temp_data : IReconnShowContent = {
            index: this._reconnCount,
            total: RECONN_LIMIT
        }
        CustomEventListener.dispatchEvent("core_notify_ws_reconnect", { "response": temp_data });

        self._reconnectHandle();
    }

    public onConfirm() {
        let self = this;
        CustomEventListener.dispatchEvent("core_notify_ws_unloading");
        console.log("DoWebSock on_ws_addr_confirm_ok 认证成功");

        // 关闭重连计时器
        // this.on_ws_reconnect_delay_close();
        self._reconnCount = 0;

        // 成功回调
        if (this._connSuccHandle) {
            console.log("DoWebSock on_ws_addr_confirm_ok 成功回调");
            this._connSuccHandle();
        }  
    }

    public onCancel() {
        let self = this;
        // 更新状态
        self._isLink = false;
        // self._isReconn = false;

        // 关闭重连计时器
        // self.on_ws_reconnect_delay_close();
        self._reconnCount = 0;
    }

    public send_pb(data: NetData) {
        let self = this;
        // console.log("DoWebSock send_pb ");
        if (!self._wsiSendBinary) {
            console.warn("DoWebSock send_pb _wsiSendBinary 异常！！！");
            return;
        }
        if (self._isLink !== true) {
            console.warn("DoWebSock send_pb 异常！！！this.is_link = " + self._isLink);
            return;
        }
        self._wsiSendBinary.send(data);
        // console.log("DoWebSock send_pb ################################### ↑↑↑↑↑↑↑↑↑↑ ");
    }

    // -----------------------------------------------------------------------------
    // 主动关闭
    private ws_clear() {
        let self = this;
        
        if (self._wsiSendBinary) {
            console.log("DoWebSock ws_clear 存在未正常关闭的ws，关闭");
            this._wsiSendBinary.close();
            this._wsiSendBinary = null;
        }
    }

    public ws_clear_interface() {
        // 如果是连接中，则断开之
        console.log("DoWebSock ws_clear_interface this._isLink = " + this._isLink);
        if (this._isLink === true) {
            this.ws_clear();
        }
    }

    // ------------------------------------------------------------------------------
    // setter/getter
    public setAllowReconn(val: boolean) {
        this._allowReconn = val;
    }

    public isLink() {
        return this._isLink;
    }

    public getUrl() {
        return this._url;
    }

    public resetReconnCount() {
        this._reconnCount = 0;
    }
}

